package wpp.cfg;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import wpp.WPPConfig;
import wpp.exception.WPPException;
import wpp.util.IOUtil;
import wpp.util.SortedList;

public class DataConfig {
	private static final Logger LOGGER = Logger.getLogger(DataConfig.class);	
	private static final String F_WP_BEANS = "wpBeans";
	
	private static JSONObject cfg;
	private static List<WPFileBean> wpBeans = Collections.synchronizedList(new ArrayList<WPFileBean>());
	private static Map<String, WPFileBean> orgUniqueNameBeanMap = Collections.synchronizedMap(new HashMap<String, WPFileBean>());
	private static List<WPFileBean> wpsSortedByCreateTime = Collections.synchronizedList(new SortedList<WPFileBean>());
	
	public static void load() throws IOException {
		readFromFile();		
	}
	
	public static void save() throws IOException {
		writeToFile();
	}
	
	public static void addWPFileBean(WPFileBean bean) {
		wpBeans.add(bean);
		orgUniqueNameBeanMap.put(bean.getOrgUniqueName(), bean);	
		wpsSortedByCreateTime.add(bean);		
	}
	
	public static Boolean isWPExistd(String uniqueName) {
		return orgUniqueNameBeanMap.containsKey(uniqueName);
	}	
	
	//from, to: start from 1
	public static List<WPFileBean> getLatestWpFileBeans(int from, int count) {
		int start = wpsSortedByCreateTime.size() - from;
		int end = start - count + 1;
		end = end >= 0 ? end : 0;
		List<WPFileBean> beans = new ArrayList<WPFileBean>();
		for(int i = start; i >= end; i -- ) {
			beans.add(wpsSortedByCreateTime.get(i));
		}
		return beans;
	}	
	
	public static List<WPFileBean> getFavoriteWpFileBeans(int count, boolean ignoreNeverFavor) {
		List<WPFileBean> sortedList = new SortedList<WPFileBean>(new Comparator<WPFileBean>() {
			@Override
			public int compare(WPFileBean o1, WPFileBean o2) {
				return (o1.getFavore() - o2.getFavore()) * -1;
			}
		});
		sortedList.addAll(wpBeans);
		List<WPFileBean> resultList = new ArrayList<WPFileBean>();
		for(int i = 0; i < count && i < sortedList.size(); i++) {
			WPFileBean bean = sortedList.get(i);
			if(bean.getFavore() != 0 || ignoreNeverFavor == false) {
				resultList.add(bean);
			} 
		}
		return resultList;		
	}
	
	public static WPFileBean getAWpFileBeanAfter(WPFileBean target) {
		if(target == null) {
			return wpsSortedByCreateTime.get(0);
		} else {
			Integer tmp = wpsSortedByCreateTime.indexOf(target) + 1;			
			if(tmp > 0 && tmp < wpsSortedByCreateTime.size()) {
				return wpsSortedByCreateTime.get(tmp);
			} else {
				return null;
			}
		}
	}
	
	//Private	
	private static void initData(String cfgStr) {		
		cfg = JSONObject.fromObject(cfgStr);
		JSONArray wpBeanArray = cfg.getJSONArray(F_WP_BEANS);		
		for(int i = 0; i < wpBeanArray.size(); i++) {
			addWPFileBean((WPFileBean) JSONObject.toBean(wpBeanArray.getJSONObject(i), WPFileBean.class));
		}
	}
	
	private static void readFromFile() throws IOException {
		InputStream in = null;
		try {
			in = new FileInputStream(WPPConfig.getCfgFile());
			String cfgStr = IOUtil.readText(in);
			LOGGER.info("Read config from file");
			if(cfgStr.length() == 0) {
				throw new WPPException("No config file found");
			} else {				
				initData(cfgStr);
			}
		} catch (IOException e) {
			throw e;
		} catch (Exception e) {
			LOGGER.error(e.getMessage(), e);
			resetCfg();
		} finally {
			in.close();
		}
	}
	
	private static void writeToFile() throws IOException {
		OutputStream out = null;
		try {
			out = new FileOutputStream(WPPConfig.getCfgFile());
			cfg.put(F_WP_BEANS, JSONArray.fromObject(wpBeans));
			IOUtil.writeText(out, cfg.toString());
			if(LOGGER.isDebugEnabled()) {
				LOGGER.debug(cfg.toString());
				LOGGER.debug("wpBeans size: " + wpBeans.size());
			}
			LOGGER.info("Write config to file");
		} finally {
			out.close();
		}
	}
	
	private static void resetCfg() throws IOException {
		cfg = new JSONObject();
		LOGGER.info("Reset config");
		writeToFile();
	}

}
